home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Programming Languages Suite
/
ProgramD2.iso
/
Borland
/
Borland C++ V5.02
/
IATHREAD.PAK
/
MDICHILD.C
< prev
next >
Wrap
C/C++ Source or Header
|
1997-05-06
|
15KB
|
496 lines
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (C) 1993-1995 Microsoft Corporation. All Rights Reserved.
//
// MODULE: mdichild.c
//
// PURPOSE:
// To implement the basic mdi child commands.
//
// FUNCTIONS:
// ChildThreadProc - Performs work for each MDI child window.
// MDIChildWndProc - Processes messages for MDI child windows.
// MsgMCCommand - Handle the WM_COMMAND messages for MDI children.
// MsgMCCreate - Initializes new MDI child window.
// MsgMCDestroy - Destroys MDI child window and frees its resources.
// MsgMCMdiActiveate - Changes menus depending on which child is active.
// CmdMCThreadSuspend - Suspends active MDI child's worker thread.
// CmdMCThreadResume - Resumes active MDI child's worker thread.
//
// COMMENTS:
//
#include <windows.h> // required for all Windows applications
#include <windowsx.h>
#include "globals.h" // prototypes specific to this application
#include <stdlib.h>
#include "resource.h"
// Child window message table definition.
static MSD rgmsd[] =
{
{WM_COMMAND, MsgMCCommand},
{WM_CREATE, MsgMCCreate},
{WM_MDIACTIVATE, MsgMCMdiActivate},
{WM_DESTROY, MsgMCDestroy}
};
static MSDI msdiChild =
{
sizeof(rgmsd) / sizeof(MSD),
rgmsd,
edwpMDIChild
};
// Child window command table definition.
static CMD rgcmd[] =
{
{IDM_THREAD_PRIORITY, CmdMCThreadPriority},
{IDM_THREAD_SUSPEND, CmdMCThreadSuspend},
{IDM_THREAD_RESUME, CmdMCThreadResume}
};
static CMDI cmdiChild =
{
sizeof(rgcmd) / sizeof(CMD),
rgcmd,
edwpMDIChild
};
//
// FUNCTION: ChildThreadProc(LPDWORD)
//
// PURPOSE: To perform work for each MDI child window.
//
// PARAMETERS:
//
//
// RETURN VALUE:
// Always returns 0.
//
// COMMENTS:
// This function executes in one thread for each MDI child window.
//
//
#pragma warn -rch
DWORD WINAPI ChildThreadProc (LPDWORD lpData)
{
PTHREAD_DATA pThreadData = (PTHREAD_DATA)lpData;
HWND hWnd;
HDC hDrawDC;
RECT rClientRect = {0};
HBRUSH hRectBrush;
HBRUSH hOldBrush;
COLORREF crRectColor;
int nRed, nGreen, nBlue;
int nLeft, nTop, nRight, nBottom;
nGreen = nBlue = 0;
while (TRUE)
{
EnterCriticalSection(&(pThreadData -> csCritSec));
if (pThreadData -> bKill == TRUE)
{
// Be sure to leave critical section before exiting!
LeaveCriticalSection (&(pThreadData -> csCritSec));
ExitThread(0);
}
// Check timeout counter and reduce this thread's priority and
// the process's priority class if needed. This prevents this
// thread/process from hogging the system.
ReducePriority (pThreadData);
// Draw rectangles in MDI child window only if it's client
// area is at least 1 pixel wide and 1 pixel tall.
hWnd = pThreadData -> hWindow;
hDrawDC = GetDC(hWnd);
GetClientRect(hWnd, &rClientRect);
if ((rClientRect.right != 0) && (rClientRect.bottom != 0))
{
// Pick a random pure color for the rectangle.
// Below is a more-optimized version of this:
// nRed = rand() % 0xFF;
// nGreen = rand() % 0xFF;
// nBlue = rand() % 0xFF;
nRed = nGreen;
nGreen = nBlue;
nBlue = rand() % 0xFF;
crRectColor = RGB(nRed, nGreen, nBlue);
hRectBrush = CreateSolidBrush(
GetNearestColor(hDrawDC,
crRectColor)
);
hOldBrush = SelectObject(hDrawDC, hRectBrush);
// Draw the rectangle
nLeft = rand() % rClientRect.right;
nTop = rand() % rClientRect.bottom;
nRight = nLeft + 20;
nBottom = nTop + 20;
Rectangle(hDrawDC, nLeft, nTop, nRight, nBottom);
// Clean up all of the resources used to draw rectangle.
SelectObject(hDrawDC, hOldBrush);
ReleaseDC(hWnd, hDrawDC);
DeleteObject(hRectBrush);
// Be sure to leave the critical section before exiting
// the while loop!
LeaveCriticalSection(&(pThreadData -> csCritSec));
}
else
{
// Go to sleep temporarily while MDI child is minimized or has no
// client area.
// Leave the critical section before sleeping. No need to
// hold it while sleeping. Note that we also have to leave the
// critical section at the end of the if() clause above.
LeaveCriticalSection(&(pThreadData -> csCritSec));
Sleep(1000);
}
}
return 0;
}
#pragma warn .rch
//
// FUNCTION: MDIChildWndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for MDI child windows.
//
// PARAMETERS:
// hwnd - window handle
// uMessage - message number
// wparam - additional information (depends on message)
// lparam - additional information (depends on message)
//
// RETURN VALUE:
// Depends on the message number.
//
// COMMENTS:
// Dispatch all messages sent to MDI child windows.
//
LRESULT CALLBACK MDIChildWndProc(HWND hwnd,
UINT uMessage,
WPARAM wparam,
LPARAM lparam)
{
return DispMessage( &msdiChild, hwnd, uMessage, wparam, lparam );
}
//
// FUNCTION: MsgMCCommand(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Handle the WM_COMMAND messages for MDI children.
//
// PARAMETERS:
// hwnd - window handle
// uMessage - WM_COMMAND (Unused)
// wparam - Contains command-specific information
// lparam - Contains command-specific information
//
// RETURN VALUE:
//
// COMMENTS:
// Dispatch all commands sent to MDI child windows.
//
#pragma argsused
LRESULT MsgMCCommand(HWND hwnd, UINT uMessage, WPARAM wparam, LPARAM lparam)
{
return DispCommand(&cmdiChild, hwnd, wparam, lparam);
}
//
// FUNCTION: MsgMCCreate(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Initializes new child window and starts its worker thread.
//
// PARAMETERS:
// hwnd - The window being created.
// uMessage - WM_CREATE (unused).
// wparam - Message specific data (unused).
// lparam - Message specific data (unused).
//
// RETURN VALUE:
// Always returns 0 - message handled.
//
// COMMENTS:
//
#pragma argsused
LRESULT MsgMCCreate(HWND hwnd, UINT uMessage, WPARAM wparam, LPARAM lparam)
{
PTHREAD_DATA pThreadData;
HANDLE hThread;
DWORD dwThreadID = 0;
// Allocate thread data block. If allocation fails, force window
// creation failure.
pThreadData = AllocThreadData();
if (pThreadData == NULL)
return -1;
// Create the child window thread suspended. This will ensure that
// the new thread doesn't try to access any of the members of the
// thread data before all members have been initialized.
// If thread couldn't be created, clean up critical section, allocated
// memory, and force window creation failure.
hThread = CreateThread(NULL,
0,
(LPTHREAD_START_ROUTINE) ChildThreadProc,
(LPVOID)pThreadData,
CREATE_SUSPENDED,
&dwThreadID);
if (hThread == NULL)
{
DeleteCriticalSection(&(pThreadData -> csCritSec));
FreeThreadData(pThreadData);
return -1;
}
// Initialize all thread block members
InitializeCriticalSection(&(pThreadData -> csCritSec));
pThreadData -> hWindow = hwnd;
pThreadData -> bKill = FALSE;
pThreadData -> hThread = hThread;
pThreadData -> dwThreadID = dwThreadID;
pThreadData -> nPriorityTimer = -1; // Timer initially deactivated
// Store a pointer to the thread data block in the extra bytes for
// convenient access.
SetWindowLong(hwnd, GWL_USERDATA, (long)pThreadData);
ResumeThread(hThread);
gcOpenChildWnds++;
return 0;
}
//
// FUNCTION: MsgMCDestroy(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: To handle the WM_DESTROY message sent to MDI child windows.
//
// PARAMETERS:
// hwnd - The window being destroyed.
// uMessage - WM_DESTROY (unused).
// wparam - Message specific data (unused).
// lparam - Message specific data (unused).
//
// RETURN VALUE:
// Always returns 0 - message handled.
//
// COMMENTS:
//
#pragma argsused
LRESULT MsgMCDestroy(HWND hwnd, UINT uMessage, WPARAM wparam, LPARAM lparam)
{
PTHREAD_DATA pThreadData;
HANDLE hThread;
BOOL fResumed;
// Get thread data block associated with this child window
pThreadData = (PTHREAD_DATA)GetWindowLong(hwnd, GWL_USERDATA);
if (pThreadData != NULL) // Should never be NULL. ASSERT better!
{
EnterCriticalSection (&(pThreadData -> csCritSec));
// Tell thread that it is time to exit
pThreadData -> bKill = TRUE;
hThread = pThreadData -> hThread;
LeaveCriticalSection(&(pThreadData -> csCritSec));
// Make sure thread is running before we wait for it to exit.
do
{
fResumed = ResumeThread(hThread);
}
while (fResumed != 0xFFFFFFFF && fResumed > 1);
// Wait for thread to exit before closing its handle and deleting
// the thread data block.
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
DeleteCriticalSection(&(pThreadData -> csCritSec));
FreeThreadData(pThreadData);
}
// Decrement number of open MDI child windows.
gcOpenChildWnds--;
return 0;
}
//
// FUNCTION: MsgMCMdiActivate(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: To change the menu on the frame window so that it is the right
// one for the MDI child window.
//
// PARAMETERS:
// hwnd - The window handing the message.
// uMessage - WM_MDIACTIVATE (unused).
// wparam - The MDI child window becoming inactive (unused).
// lparam - The MDI child window becoming active.
//
// RETURN VALUE:
// Always returns 0 - message handled.
//
// COMMENTS:
// If the window becoming active is an MDI chil window, set the menu to
// document menu; otherwise, set it to the initial frame menu.
//
#pragma argsused
LRESULT MsgMCMdiActivate(HWND hwnd,
UINT uMessage,
WPARAM wparam,
LPARAM lparam)
{
HWND hActiveWnd = (HWND)lparam; // Window becoming active
HMENU hNewMenu;
HMENU hNewWindowMenu;
// If this window is becoming active, set the menu to document window;
// otherwise set it to the initial frame window.
if (hwnd == hActiveWnd)
{
hNewMenu = ghDocMenu;
hNewWindowMenu = GetSubMenu (ghDocMenu, DOCWINDOWMENU);
}
else
{
hNewMenu = ghInitMenu;
hNewWindowMenu = GetSubMenu (ghInitMenu, INITWINDOWMENU);
}
SendMessage (ghwndMDIClient,
WM_MDISETMENU,
(WPARAM)hNewMenu,
(LPARAM)hNewWindowMenu);
DrawMenuBar (ghwndFrame);
return 0;
}
//
// FUNCTION: CmdMCThreadSuspend(HWND, WORD, WORD, HWND)
//
// PURPOSE: To suspend the thread associated with a given child window.
//
// PARAMETERS:
// hwnd - The window handling the command.
// wCommand - IDM_THREAD_SUSPEND (unused).
// wNotify - Notification number (unused)
// hwndCtrl - NULL (unused).
//
// RETURN VALUE:
// Always returns 0 - command handled.
//
// COMMENTS:
//
#pragma argsused
LRESULT CmdMCThreadSuspend(HWND hwnd,
WORD wCommand,
WORD wNotify,
HWND hwndCtrl)
{
PTHREAD_DATA pThreadData;
pThreadData = (PTHREAD_DATA)GetWindowLong(hwnd, GWL_USERDATA);
if (pThreadData != NULL) // Should never be NULL ASSERT better
{
EnterCriticalSection(&(pThreadData -> csCritSec));
// Call SuspendThread inside critical section to make sure thread
// is not in the critical section. Otherwise, a deadlock will occur
// if you suspend the thread while it is in the critical section and
// try to claim the critical section before the thread is resumed.
SuspendThread(pThreadData -> hThread);
LeaveCriticalSection(&(pThreadData -> csCritSec));
}
return 0;
}
//
// FUNCTION: CmdMCThreadResume(HWND, WORD, WORD, HWND)
//
// PURPOSE: To resume the thread associated with a given child window.
//
// PARAMETERS:
// hwnd - The window handling the command.
// wCommand - IDM_THREAD_RESUME (unused).
// wNotify - Notification number (unused)
// hwndCtrl - NULL (unused).
//
// RETURN VALUE:
// Always returns 0 - command handled.
//
// COMMENTS:
//
//
#pragma argsused
LRESULT CmdMCThreadResume(HWND hwnd,
WORD wCommand,
WORD wNotify,
HWND hwndCtrl)
{
PTHREAD_DATA pThreadData;
HANDLE hThread;
pThreadData = (PTHREAD_DATA)GetWindowLong(hwnd, GWL_USERDATA);
if (pThreadData != NULL) // Should never be NULL ASSERT better
{
// Get thread's handle. Use critical section in case thread
// is not suspended. Suspended thread won't be in critical section
// because we suspended it while we were in the critical section.
EnterCriticalSection(&(pThreadData -> csCritSec));
hThread = pThreadData -> hThread;
LeaveCriticalSection(&(pThreadData -> csCritSec));
ResumeThread (hThread);
}
return 0;
}